home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / unit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-02  |  50.6 KB  |  2,017 lines  |  [TEXT/KAHL]

  1. /* Units in Xconq.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. #include "conq.h"
  11.  
  12. /* This is not a limit, just sets initial allocation of unit objects
  13.    and how many additional to get if more are needed.  This can be
  14.    tweaked for more frequent but smaller allocation, or less frequent
  15.    but larger and possibly space-wasting allocation. */
  16.  
  17. #ifndef INITMAXUNITS
  18. #define INITMAXUNITS 200
  19. #endif
  20.  
  21. static int compare_units PROTO ((Unit *unit1, Unit *unit2));
  22.  
  23. static int compare_units_by_keys PROTO ((const void *e1, const void *e2));
  24.  
  25. /* The list of available units. */
  26.  
  27. Unit *freeunits;
  28.  
  29. /* The global linked list of all units. */
  30.  
  31. Unit *unitlist;
  32.  
  33. /* A scratch global. */
  34.  
  35. Unit *tmpunit;
  36.  
  37. /* Buffers for descriptions of units. */
  38.  
  39. /* We use several and rotate among them; this is so multiple calls in
  40.    a single printf will work as expected.  Not elegant, but simple and
  41.    sufficient. */
  42.  
  43. #define NUMSHORTBUFS 3
  44.  
  45. int curshortbuf = 0;
  46.  
  47. char *shortbufs[NUMSHORTBUFS] = { NULL, NULL, NULL };
  48.  
  49. char utypenamen[100];
  50.  
  51. char *actorstatebuf = NULL;
  52.  
  53. /* Total number of units in existence. */
  54.  
  55. int numunits = 0;
  56.  
  57. /* The next number to use for a unit id. */
  58.  
  59. int nextid = 1;            /* next number to be used for ids */
  60.  
  61. /* buffer for remembering occupant death */
  62.  
  63. int *occdeath = NULL;
  64.  
  65. /* Have units died since dead unit lists made */
  66.  
  67. int recent_dead_flushed = TRUE;
  68.  
  69. int totunits;
  70. int *totutypes;
  71.  
  72. /* Grab a block of unit objects to work with. */
  73.  
  74. void
  75. allocate_unit_block()
  76. {
  77.     int i;
  78.     Unit *unitblock = (Unit *) xmalloc(INITMAXUNITS * sizeof(Unit));
  79.  
  80.     for (i = 0; i < INITMAXUNITS; ++i) {
  81.     unitblock[i].id = -1;
  82.     unitblock[i].next = &unitblock[i+1];
  83.     }
  84.     unitblock[INITMAXUNITS-1].next = NULL;
  85.     freeunits = unitblock;
  86.     Dprintf("Allocated space for %d units.\n", INITMAXUNITS);
  87. }
  88.  
  89. /* Init gets a first block of units, and sets up the "independent side" list,
  90.    since newly created units will appear on it. */
  91.  
  92. void
  93. init_units()
  94. {
  95.     unitlist = NULL;
  96.     allocate_unit_block();
  97.     init_side_unithead(indepside);
  98. }
  99.  
  100. /* The primitive unit creator, called by regular creator and also used to
  101.    make the dummy units that sit at the heads of the per-side unit lists. */
  102.  
  103. Unit *
  104. create_bare_unit(type)
  105. int type;
  106. {
  107.     Unit *newunit;
  108.  
  109.     /* If our free list is empty, go and get some more units. */
  110.     if (freeunits == NULL) {
  111.     allocate_unit_block();
  112.     }
  113.     /* Take the first unit off the free list. */
  114.     newunit = freeunits;
  115.     freeunits = freeunits->next;
  116.     /* Give it a valid type... */
  117.     newunit->type = type;
  118.     /* ...but an invalid id. */
  119.     newunit->id = -1;
  120.     return newunit;
  121. }
  122.  
  123. /* The regular unit creation routine.  All the slots should have something
  124.    reasonable in them, since individual units objects see a lot of reuse. */
  125.  
  126. Unit *
  127. create_unit(type, makebrains)
  128. int type, makebrains;
  129. {
  130.     int m;
  131.     Unit *newunit;
  132.  
  133.     if (totutypes == NULL) {
  134.         totutypes = (int *) xmalloc(MAXUTYPES * sizeof(int));
  135.     }
  136.     /* Test whether we've hit any designer-specified limits. */
  137.     if ((u_type_in_game_max(type) >= 0
  138.      && totutypes[type] >= u_type_in_game_max(type))
  139.     || (g_units_in_game_max() >= 0
  140.         && totunits >= g_units_in_game_max())) {
  141.     return NULL;
  142.     }
  143.     /* Allocate the unit object.  Xconq will fail instead of returning null. */
  144.     newunit = create_bare_unit(type);
  145.     /* Init all the slots to distinguishable values.  The unit is not
  146.        necessarily newly allocated, so we have to hit all of its slots. */
  147.     newunit->id = nextid++;
  148.     newunit->name = NULL;
  149.     /* Number == 0 means unit is unnumbered. */
  150.     newunit->number = 0;
  151.     /* Outside the world. */
  152.     newunit->x = newunit->y = -1;
  153.     /* At ground level. */
  154.     newunit->z = 0;
  155.     /* Units default to being independent. */
  156.     newunit->side = NULL;
  157.     /* Create at max hp, let others reduce if necessary. */
  158.     newunit->hp = newunit->hp2 = u_hp(type);
  159.     /* Create fully functional, let other routines set incompleteness. */
  160.     newunit->cp = u_cp(type);
  161.     /* Not in a transport. */
  162.     newunit->transport = NULL;
  163. #ifndef MSDOS /* (should not be a separate case?) */
  164. #if (MAXMTYPES > 2)
  165.     /* Note that the space never needs to be freed. */
  166.     if (newunit->supply == NULL && nummtypes > 0) {
  167.     newunit->supply = (short *) xmalloc(nummtypes * sizeof(short));
  168.     }
  169. #endif
  170. #else /* MSDOS */
  171.     /* Note that the space never needs to be freed. */
  172.     if (newunit->supply == NULL && nummtypes > 0) {
  173.     newunit->supply = (short *) xmalloc(nummtypes * sizeof(short));
  174.     }
  175. #endif /* MSDOS */
  176.     /* In any case, zero out all the supply values. */
  177.     for_all_material_types(m) newunit->supply[m] = 0;
  178.     /* Will allocate tooling state when actually needed. */
  179.     newunit->tooling = NULL;
  180.     /* Will allocate opinions when actually needed. */
  181.     newunit->opinions = NULL;
  182.     if (makebrains) {
  183.     init_unit_actorstate(newunit);
  184.     init_unit_plan(newunit);
  185.     } else {
  186.     newunit->act = NULL;
  187.     newunit->plan = NULL;
  188.     }
  189.     newunit->occupant = NULL;
  190.     newunit->nexthere = NULL;
  191.     /* Glue this unit into the list of independent units. */
  192.     newunit->next = newunit;
  193.     newunit->prev = newunit;
  194.     insert_unit(indepside->unithead, newunit);
  195.     newunit->unext = unitlist;
  196.     unitlist = newunit;
  197.     /* Init more random slots. */
  198.     newunit->prevx = newunit->prevy = -1;
  199.     newunit->hook = lispnil;
  200.     newunit->aihook = NULL;
  201.     /* Add to the global unit count (is this really necessary?). */
  202.     ++numunits;
  203.     return newunit;
  204. }
  205.  
  206. void
  207. init_unit_tooling(unit)
  208. Unit *unit;
  209. {
  210.     unit->tooling = (short *) xmalloc(numutypes * sizeof(short));
  211. }
  212.  
  213. void
  214. init_unit_opinions(unit)
  215. Unit *unit;
  216. {
  217.     if (u_has_opinions(unit->type)) {
  218.     if (unit->opinions == NULL)
  219.       unit->opinions = (short *) xmalloc(numsides * sizeof(short));
  220.     /* Opinions are now all neutral. */
  221.     } else {
  222.     if (unit->opinions != NULL)
  223.       free(unit->opinions);
  224.     unit->opinions = NULL;
  225.     }
  226. }
  227.  
  228. /* Alter the actorstate object to be correct for this unit. */
  229.  
  230. void
  231. init_unit_actorstate(unit)
  232. Unit *unit;
  233. {
  234.     if (u_acp(unit->type) > 0 && unit->cp > 0) {
  235.     /* Might already have an actorstate, don't realloc if so. */
  236.     if (unit->act == NULL)
  237.       unit->act = (ActorState *) xmalloc(sizeof(ActorState));
  238.     /* Indicate that the action points have not been set. */
  239.     unit->act->acp = u_acp_min(unit->type) - 1;
  240.     /* Flag the action as undefined. */
  241.     unit->act->nextaction.type = A_NONE;
  242.     } else {
  243.     if (unit->act != NULL)
  244.       free(unit->act);
  245.     unit->act = NULL;
  246.     }
  247. }
  248.  
  249. /* Every unit that can act needs a plan object, types that can't act
  250.    should have it cleared out. */
  251.  
  252. void
  253. init_unit_plan(unit)
  254. Unit *unit;
  255. {
  256.     if (u_acp(unit->type) > 0 && unit->cp > 0) {
  257.     /* Might already have a plan, so don't always realloc. */
  258.     if (unit->plan == NULL) {
  259.         unit->plan = create_plan();
  260.     }
  261.     /* Put the plan into a default state, side will work it up later. */
  262.     unit->plan->type = PLAN_NONE;
  263.     unit->plan->creationturn = g_turn();
  264.     unit->plan->asleep = unit->plan->reserve = unit->plan->delayed = FALSE;
  265.     clear_task_agenda(unit->plan);
  266.     /* Allow AIs to make this unit do things. */
  267.     unit->plan->aicontrol = TRUE;
  268.     /* Enable supply alarms by default. */
  269.     unit->plan->supply_alarm = TRUE;
  270.     } else {
  271.     /* Brainless units don't need anything, can free up plan. */
  272.     if (unit->plan != NULL) {
  273.         free_plan(unit->plan);
  274.     }
  275.     unit->plan = NULL;
  276.     }
  277. }
  278.  
  279. /* A designer can call this to create an arbitrary unit during the game. */
  280.  
  281. Unit *
  282. designer_create_unit(side, u, s, x, y)
  283. Side *side;
  284. int u, s, x, y;
  285. {
  286.     Unit *newunit;
  287.     Side *side2;
  288.  
  289.     if (!type_can_occupy_cell(u, x, y))
  290.       return NULL;
  291.     newunit = create_unit(u, TRUE);
  292.     if (newunit != NULL) {
  293.     if (s != 0) {
  294.         side2 = side_n(s);
  295.         if (unit_allowed_on_side(newunit, side2)) {
  296.             set_unit_side(newunit, side2);
  297.             /* (should ensure that any changed counts are set correctly also) */
  298.         }
  299.     }
  300.     init_supply(newunit);
  301.     if (can_occupy_cell(newunit, x, y)) {
  302.         enter_cell(newunit, x, y);
  303.     } else {
  304.         /* what? */
  305.     }
  306.     see_exact(side, x, y);
  307.     update_cell_display(side, x, y, TRUE);
  308.     update_unit_display(side, newunit, TRUE);
  309.     return newunit;
  310.     } else {
  311.     return NULL;
  312.     }
  313. }
  314.  
  315. /* Changing a unit's type has many effects. */
  316.  
  317. void
  318. change_unit_type(unit, newtype, reason)
  319. Unit *unit;
  320. int newtype, reason;
  321. {
  322.     int oldtype = unit->type, oldhp = unit->hp;
  323.     PastUnit *pastunit;
  324.  
  325.     /* Don't do anything if we're "changing" to the same type. */
  326.     if (oldtype == newtype)
  327.       return;
  328.     pastunit = change_unit_to_past_unit(unit);
  329.     record_event(reason, -1, pastunit->id, unit->id);
  330.     /* Do the actual change. */
  331.     unit->type = newtype;
  332.     /* Set the new hp to the same ratio of max as the unit had before.
  333.        Caller can tweak to something else if necessary. */
  334.     unit->hp = (oldhp * u_hp_max(newtype)) / u_hp_max(oldtype);
  335.     /* Need to guarantee a positive value though. */
  336.     if (unit->hp < 1)
  337.       unit->hp = 1;
  338.     /* (should modify side counts) */
  339.     if (!type_allowed_on_side(newtype, unit->side)) {
  340.         if (type_allowed_on_side(newtype, NULL)) {
  341.         unit_changes_side(unit, NULL, -1, -1);
  342.     } else {
  343.         run_warning("Leaving unit on disallowed side");
  344.     }
  345.     }
  346.     /* Unit will always need a new number. */
  347.     assign_unit_number(unit);
  348.     init_unit_opinions(unit);
  349.     init_unit_actorstate(unit);
  350.     init_unit_plan(unit);
  351.     unit->aihook = NULL;
  352. }
  353.  
  354. int
  355. max_builds(u)
  356. int u;
  357. {
  358.     int u2;
  359.  
  360.     for_all_unit_types(u2) {
  361.     if (could_create(u, u2)) return 1;
  362.     }
  363.     return 0;
  364. }
  365.  
  366. /* A unit occupies a cell by adding itself to the list of occupants.
  367.    It will not occupy a transport even if one is at this position
  368.    (other code should have taken care of this case already)
  369.    If something goes wrong, return false.  This routine is heavily used. */
  370.  
  371. int
  372. enter_cell(unit, x, y)
  373. Unit *unit;
  374. int x, y;
  375. {
  376.     register int u = unit->type, ustack, u2stack;
  377.     Unit *unit2, *topunit = unit_at(x, y), *prevunit = NULL, *nextunit = NULL;
  378.  
  379. #ifdef DEBUGGING
  380.     /* Not necessarily an error, but indicative of bugs elsewhere. */
  381.     if (unit->x >= 0 || unit->y >= 0) {
  382.     run_warning("unit %d occupying cell (%d, %d), was at (%d %d)",
  383.             unit->id, x, y, unit->x, unit->y);
  384.     }
  385. #endif /* DEBUGGING */
  386.     /* Always check this one, but not necessarily fatal. */
  387.     if (!inside_area(x, y)) {
  388.     run_warning("No cell at %d,%d, %s can't enter it",
  389.             x, y, unit_desig(unit));
  390.     /* Let the unit remain off-world. */
  391.     return FALSE;
  392.     }
  393.     if (!can_occupy_cell(unit, x, y)) {
  394.     run_warning("Cell at %d,%d is too full for %s", x, y, unit_desig(unit));
  395.     /* Let the unit remain off-world. */
  396.     return FALSE;
  397.     }
  398.     if (topunit) {
  399.         /* Insert the entering unit into the stack at its correct position. */
  400.         ustack = u_stack_order(u);
  401.         for_all_stack(x, y, unit2) {
  402.         u2stack = u_stack_order(unit2->type);
  403.         if (ustack > u2stack
  404.         || (ustack == u2stack && unit->id < unit2->id)) {
  405.         nextunit = unit2;
  406.         if (unit2 == topunit) topunit = unit;
  407.         break;
  408.         }
  409.         prevunit = unit2;
  410.         }
  411.         if (prevunit != NULL) prevunit->nexthere = unit;
  412.     } else {
  413.         topunit = unit;
  414.     }
  415.     unit->nexthere = nextunit;
  416.     set_unit_at(x, y, topunit);
  417.     /* Set the location slots now. */
  418.     enter_cell_aux(unit, x, y);
  419.     /* Inevitable side-effect of appearing in the new location. */
  420.     all_see_occupy(unit, x, y, TRUE);
  421.     return TRUE;
  422. }
  423.  
  424. /* Return true if the given unit can fit onto the given cell. */
  425.  
  426. /* (should eventually account for variable-size units) */
  427.  
  428. int
  429. can_occupy_cell(unit, x, y)
  430. Unit *unit;
  431. int x, y;
  432. {
  433.     int u = unit->type, u2, u3, t = terrain_at(x, y), numthistype = 0, fullness = 0;
  434.     int tcap, utcap;
  435.     int numtypes[MAXUTYPES];
  436.     Unit *unit2;
  437.  
  438.     if (unit == NULL) run_error("null unit?");  /* should never happen */
  439.     tcap = t_capacity(t);
  440.     utcap = ut_capacity_x(u, t);
  441.     if (tcap <= 0 && utcap <= 0) return FALSE;
  442.     for_all_unit_types(u3) numtypes[u3] = 0;
  443.     for_all_stack(x, y, unit2) {
  444.     u2 = unit2->type;
  445.     ++numtypes[u2];
  446.     if (u2 == u) ++numthistype;
  447.     /* Only count against fullness if exclusive capacity exceeded. */
  448.     if (numtypes[u2] > ut_capacity_x(u2, t)) {
  449.         fullness += ut_size(u2, t);
  450.     }
  451.     }
  452.     /* Unit can be in this cell if there is dedicated space. */
  453.     if (numthistype + 1 <= utcap) return TRUE;
  454.     /* Otherwise decide on the basis of fullness. */
  455.     return (fullness + ut_size(u, t) <= tcap);
  456. }
  457.  
  458. int
  459. type_can_occupy_cell(u, x, y)
  460. int u, x, y;
  461. {
  462.     int t = terrain_at(x, y), u2, u3, numthistype = 0, fullness = 0;
  463.     int tcap, utcap;
  464.     int numtypes[MAXUTYPES];
  465.     Unit *unit2;
  466.  
  467.     tcap = t_capacity(t);
  468.     utcap = ut_capacity_x(u, t);
  469.     if (tcap <= 0 && utcap <= 0) return FALSE;
  470.     for_all_unit_types(u3) numtypes[u3] = 0;
  471.     for_all_stack(x, y, unit2) {
  472.     u2 = unit2->type;
  473.     ++numtypes[u2];
  474.     if (u2 == u) ++numthistype;
  475.     /* Only count against fullness if exclusive capacity exceeded. */
  476.     if (numtypes[u2] > ut_capacity_x(u2, t)) {
  477.         fullness += ut_size(u2, t);
  478.     }
  479.     }
  480.     /* Unit can be in this cell if there is dedicated space. */
  481.     if (numthistype + 1 <= utcap) return TRUE;
  482.     /* Otherwise decide on the basis of fullness. */
  483.     return (fullness + ut_size(u, t) <= tcap);
  484. }
  485.  
  486. /* Similar, but don't count a specific given unit when calculating. */
  487.  
  488. int
  489. can_occupy_cell_without(unit, x, y, unit3)
  490. Unit *unit, *unit3;
  491. int x, y;
  492. {
  493.     int u = unit->type, u2, u3, t = terrain_at(x, y), numthistype = 0, fullness = 0;
  494.     int tcap, utcap;
  495.     int numtypes[MAXUTYPES];
  496.     Unit *unit2;
  497.  
  498.     if (unit == NULL) run_error("null unit?");  /* should never happen */
  499.     tcap = t_capacity(t);
  500.     utcap = ut_capacity_x(u, t);
  501.     if (tcap <= 0 && utcap <= 0) return FALSE;
  502.     for_all_unit_types(u3) numtypes[u3] = 0;
  503.     for_all_stack(x, y, unit2) {
  504.     if (unit2 == unit3) continue;
  505.     u2 = unit2->type;
  506.     ++numtypes[u2];
  507.     if (u2 == u) ++numthistype;
  508.     /* Only count against fullness if exclusive capacity exceeded. */
  509.     if (numtypes[u2] > ut_capacity_x(u2, t)) {
  510.         fullness += ut_size(u2, t);
  511.     }
  512.     }
  513.     /* Unit can be in this cell if there is dedicated space. */
  514.     if (numthistype + 1 <= utcap) return TRUE;
  515.     /* Otherwise decide on the basis of fullness. */
  516.     return (fullness + ut_size(u, t) <= tcap);
  517. }
  518.  
  519. int
  520. type_can_occupy_cell_without(u, x, y, unit3)
  521. int u, x, y;
  522. Unit *unit3;
  523. {
  524.     int t = terrain_at(x, y), u2, u3, numthistype = 0, fullness = 0;
  525.     int tcap, utcap;
  526.     int numtypes[MAXUTYPES];
  527.     Unit *unit2;
  528.  
  529.     tcap = t_capacity(t);
  530.     utcap = ut_capacity_x(u, t);
  531.     if (tcap <= 0 && utcap <= 0) return FALSE;
  532.     for_all_unit_types(u3) numtypes[u3] = 0;
  533.     for_all_stack(x, y, unit2) {
  534.     if (unit2 == unit3) continue;
  535.     u2 = unit2->type;
  536.     ++numtypes[u2];
  537.     if (u2 == u) ++numthistype;
  538.     /* Only count against fullness if exclusive capacity exceeded. */
  539.     if (numtypes[u2] > ut_capacity_x(u2, t)) {
  540.         fullness += ut_size(u2, t);
  541.     }
  542.     }
  543.     /* Unit can be in this cell if there is dedicated space. */
  544.     if (numthistype + 1 <= utcap) return TRUE;
  545.     /* Otherwise decide on the basis of fullness. */
  546.     return (fullness + ut_size(u, t) <= tcap);
  547. }
  548.  
  549. /* Recursive helper to update everybody's position.  This should be one of
  550.    two routines that modify actual unit positions (leaving is the other). */
  551.  
  552. void
  553. enter_cell_aux(unit, x, y)
  554. Unit *unit;
  555. int x, y;
  556. {
  557.     int u = unit->type, dir, x1, y1, tmpz;
  558.     Unit *occ;
  559.     Side *side = unit->side;
  560.  
  561. #ifdef DEBUGGING
  562.     /* Not necessarily an error, but indicative of bugs elsewhere. */
  563.     if (unit->x >= 0 || unit->y >= 0) {
  564.     run_warning("unit %d occupying cell (%d, %d), was at (%d %d)",
  565.             unit->id, x, y, unit->x, unit->y);
  566.     }
  567. #endif /* DEBUGGING */
  568.     /* Actually set the unit position. */
  569.     unit->x = x;  unit->y = y;
  570.     /* Adjust the altitude if nonzero. */
  571.     if (unit->z != 0) {
  572.     if (unit->z & 1 == 0) {
  573.         tmpz = unit->z / 2;
  574.         tmpz = min(tmpz, ut_alt_max(u, terrain_at(x, y)));
  575.         tmpz = max(tmpz, ut_alt_min(u, terrain_at(x, y)));
  576.         unit->z = tmpz * 2;
  577.     } else {
  578.         /* (still on the same connection?) */
  579.     }
  580.     }
  581.     /* Increment viewing coverage, if unit is complete and can see out
  582.        of its transport. */
  583.     if (completed(unit)
  584.         && (unit->transport == NULL
  585.         || uu_occ_can_see(u, unit->transport->type))) {
  586.     cover_area(unit->side, unit, x, y, 1);
  587.     /* If vision range is 0, allow glimpses of adjacent cell terrain.
  588.        This applies to terrain only, adjacent units cannot be seen. */
  589.     if (u_vision_range(u) == 0
  590.         && unit->transport == NULL
  591.         && !g_see_all()
  592.         && !g_terrain_seen()
  593.         && side != NULL) {
  594.         for_all_directions(dir) {
  595.         if (point_in_dir(x, y, dir, &x1, &y1)) {
  596.             if (terrain_view(side, x1, y1) == UNSEEN) {
  597.             set_terrain_view(side, x1, y1,
  598.                      buildtview(terrain_at(x1, y1)));
  599.             update_cell_display(side, x1, y1, TRUE);
  600.             }
  601.         }
  602.         }
  603.     }
  604.     }
  605.     /* Do for all the occupants too, recursively. */
  606.     for_all_occupants(unit, occ) {
  607.     enter_cell_aux(occ, x, y);
  608.     }
  609. }
  610.  
  611. /* Decide whether the given unit can actually be in the given transport. */
  612.  
  613. /* (this still needs to account for multipart units) */
  614.  
  615. int
  616. can_occupy(unit, transport)
  617. Unit *transport, *unit;
  618. {
  619.     return can_carry(transport, unit);
  620. }
  621.  
  622. int
  623. can_carry(transport, unit)
  624. Unit *transport, *unit;
  625. {
  626.     int u = unit->type, u2 = transport->type, u3, o;
  627.     int numthistype = 0, numalltypes = 0, occvolume = 0;
  628.     int ucap, uucap;
  629.     int numtypes[MAXUTYPES];
  630.     Unit *occ;
  631.  
  632.     /* Intercept nonsensical arguments. */
  633.     if (transport == unit)
  634.       return FALSE;
  635.     /* Don't allow occupation of incomplete transports unless the unit is
  636.        of a type that can help complete. */
  637.     if (!completed(transport) && uu_acp_to_build(u, u2) < 1)
  638.       return FALSE;
  639.     if (unit->occupant != NULL && !uu_occ_can_have_occs(u, u2))
  640.       return FALSE;
  641.     ucap = u_capacity(u2);
  642.     uucap = uu_capacity_x(u2, u);
  643.     if (ucap <= 0 && uucap <= 0)
  644.       return FALSE;
  645.     for_all_unit_types(u3) numtypes[u3] = 0;
  646.     /* Compute the transport's fullness. */
  647.     for_all_occupants(transport, occ) {
  648.         o = occ->type;
  649.     ++numalltypes;
  650.     ++numtypes[occ->type];
  651.     if (o == u) ++numthistype;
  652.     /* Only count against fullness if exclusive capacity exceeded. */
  653.     if (numtypes[o] > uu_capacity_x(u2, o)) {
  654.         occvolume += uu_size(o, u2);
  655.     }
  656.     }
  657.     /* Can carry if dedicated space available. */
  658.     if (numthistype + 1 <= uucap) return TRUE;
  659.     /* Check upper limit on count of occupants of this type. */
  660.     if (uu_occ_max(u2, u) >= 0
  661.         && numthistype + 1 - uucap > uu_occ_max(u2, u))
  662.       return FALSE;
  663.     /* Check upper limit on count of occupants of all types. */
  664.     if (u_occ_total_max(u2) >= 0
  665.         && numalltypes + 1 > u_occ_total_max(u2))
  666.       return FALSE;
  667.     /* Can carry if general unit hold has room. */
  668.     return (occvolume + uu_size(u, u2) <= ucap);
  669. }
  670.  
  671. /* (should share with prev routine somehow) */
  672.  
  673. int
  674. type_can_occupy(u, transport)
  675. int u;
  676. Unit *transport;
  677. {
  678.     int u2 = transport->type, u3, o;
  679.     int numthistype = 0, numalltypes = 0, occvolume = 0;
  680.     int ucap, uucap;
  681.     int numtypes[MAXUTYPES];
  682.     Unit *occ;
  683.  
  684.     /* Don't allow occupation of incomplete transports unless the unit is
  685.        of a type that can help complete. */
  686.     if (!completed(transport) && uu_acp_to_build(u, u2) < 1)
  687.       return FALSE;
  688.     ucap = u_capacity(u2);
  689.     uucap = uu_capacity_x(u2, u);
  690.     if (ucap <= 0 && uucap <= 0)
  691.       return FALSE;
  692.     for_all_unit_types(u3) numtypes[u3] = 0;
  693.     /* Compute the transport's fullness. */
  694.     for_all_occupants(transport, occ) {
  695.         o = occ->type;
  696.     ++numalltypes;
  697.     ++numtypes[o];
  698.     if (o == u) ++numthistype;
  699.     /* Only count against fullness if exclusive capacity exceeded. */
  700.     if (numtypes[o] > uu_capacity_x(u2, o)) {
  701.         occvolume += uu_size(o, u2);
  702.     }
  703.     }
  704.     /* Can carry if dedicated space available. */
  705.     if (numthistype + 1 <= uucap)
  706.       return TRUE;
  707.     /* Check upper limit on count of occupants of this type. */
  708.     if (uu_occ_max(u2, u) >= 0
  709.         && numthistype + 1 - uucap > uu_occ_max(u2, u))
  710.       return FALSE;
  711.     /* Check upper limit on count of occupants of all types. */
  712.     if (u_occ_total_max(u2) >= 0
  713.         && numalltypes + 1 > u_occ_total_max(u2))
  714.       return FALSE;
  715.     /* Can carry if general unit hold has room. */
  716.     return (occvolume + uu_size(u, u2) <= ucap);
  717. }
  718.  
  719. int
  720. can_occupy_type(unit, u2)
  721. Unit *unit;
  722. int u2;
  723. {
  724.     int u = unit->type;
  725.  
  726.     /* Can occupy if nonzero reserved capacity for this type. */
  727.     if (uu_capacity_x(u2, u) > 0)
  728.       return TRUE;
  729.     /* Can occupy if general unit hold has room for at least one unit. */
  730.     return (uu_size(u, u2) <= u_capacity(u2));
  731. }
  732.  
  733. int
  734. can_carry_type(transport, u)
  735. Unit *transport;
  736. int u;
  737. {
  738.     return type_can_occupy(u, transport);
  739. }
  740.  
  741. /* Units become occupants by linking into the transport's occupant list. */
  742.  
  743. void
  744. enter_transport(unit, transport)
  745. Unit *unit, *transport;
  746. {
  747.     int u = unit->type, ustack, u2stack;
  748.     Unit *unit2, *topunit = transport->occupant;
  749.     Unit *prevunit = NULL, *nextunit = NULL;
  750.  
  751.     if (unit == transport) {
  752.         run_error("Unit is trying to enter itself");
  753.     }
  754.     if (topunit) {
  755.         /* Insert the entering unit into the occupant list at
  756.        its correct position. */
  757.         ustack = u_stack_order(u);
  758.         for_all_occupants(transport, unit2) {
  759.         u2stack = u_stack_order(unit2->type);
  760.         if (ustack > u2stack
  761.         || (ustack == u2stack && unit->id < unit2->id)) {
  762.         nextunit = unit2;
  763.         if (unit2 == topunit) topunit = unit;
  764.         break;
  765.         }
  766.         prevunit = unit2;
  767.         }
  768.         if (prevunit != NULL) prevunit->nexthere = unit;
  769.     } else {
  770.         topunit = unit;
  771.     }
  772.     unit->nexthere = nextunit;
  773.     transport->occupant = topunit;
  774.     /* Point from the unit back to its transport. */
  775.     unit->transport = transport;
  776.     /* Set the passenger's coords to match the transport's. */
  777.     enter_cell_aux(unit, transport->x, transport->y);
  778.     /* Others might be watching. */
  779.     all_see_occupy(unit, transport->x, transport->y, FALSE);
  780. }
  781.  
  782. /* Unit departs from a cell by zeroing out pointer if in cell or by being
  783.    removed from the list of transport occupants. */
  784.  
  785. /* Dead units (hp = 0) may be run through here, so don't error out. */
  786.  
  787. void
  788. leave_cell(unit)
  789. Unit *unit;
  790. {
  791.     int ux = unit->x, uy = unit->y;
  792.     Unit *transport = unit->transport, *other;
  793.  
  794.     if (ux < 0 || uy < 0) {
  795.     /* Sometimes called twice */
  796.     } else if (transport != NULL) {
  797.     leave_transport(unit);
  798.     leave_cell_aux(unit);
  799.     all_see_leave(unit, ux, uy, FALSE);
  800.     /* not all_see_cell here because can't see inside transports */
  801.     update_unit_display(transport->side, transport, TRUE);
  802.     } else {
  803.     /* Unsplice ourselves from the list of units in this cell. */
  804.     if (unit == unit_at(ux, uy)) {
  805.         set_unit_at(ux, uy, unit->nexthere);
  806.     } else {
  807.         for_all_stack(ux, uy, other) {
  808.         if (unit == other->nexthere) {
  809.             other->nexthere = other->nexthere->nexthere;
  810.             break;
  811.         }
  812.        } 
  813.     }
  814.     /* Bash this now-spurious link. */
  815.     unit->nexthere = NULL;
  816.     /* Now bash the coords. */
  817.     leave_cell_aux(unit);
  818.     /* Now let everybody observe that the unit is gone. */
  819.     all_see_leave(unit, ux, uy, TRUE);
  820.     }
  821. }
  822.  
  823. /* When leaving, remove view coverage, record old position, and then
  824.    trash the old coordinates just in case.  Catches many bugs.  Do
  825.    this for all the occupants as well. */
  826.  
  827. void
  828. leave_cell_aux(unit)
  829. Unit *unit;
  830. {
  831.     Unit *occ;
  832.  
  833.     if (unit->x < 0 && unit->y < 0) {
  834.     run_warning("unit has already left the cell");
  835.     }
  836.     /* Decrement viewing coverage around our about-to-be-old location. */
  837.     if (completed(unit)
  838.         && (unit->transport == NULL
  839.        || uu_occ_can_see(unit->type, unit->transport->type))) {
  840.     cover_area(unit->side, unit, unit->x, unit->y, -1);
  841.     }
  842.     /* Stash the old coords. */
  843.     unit->prevx = unit->x; unit->prevy = unit->y;
  844.     /* Set to a recognizable value. */
  845.     unit->x = -1;  unit->y = -1;
  846.     /* Make any occupants leave too. */
  847.     for_all_occupants(unit, occ) {
  848.     leave_cell_aux(occ);
  849.     }
  850. }
  851.  
  852. /* Disembarking unlinks from the list of passengers only, leaves the unit
  853.    hanging in limbo, so should have it occupy something immediately. */
  854.  
  855. void
  856. leave_transport(unit)
  857. Unit *unit;
  858. {
  859.     Unit *transport = unit->transport, *occ;
  860.  
  861.     if (unit == transport) {
  862.         run_error("Unit is trying to leave itself");
  863.     }
  864.     if (unit == transport->occupant) {
  865.     transport->occupant = unit->nexthere;
  866.     } else {
  867.     for_all_occupants(transport, occ) {
  868.         if (unit == occ->nexthere) {
  869.         occ->nexthere = occ->nexthere->nexthere;
  870.         break;
  871.         }
  872.     }
  873.     }
  874.     /* Bash the now-spurious link. */
  875.     unit->transport = NULL;
  876. }
  877.  
  878. /* Given an overfull unit, spew out occupants until back within limits. */
  879.  
  880. void
  881. eject_excess_occupants(unit)
  882. Unit *unit;
  883. {
  884.     int u, u2 = unit->type, overfull = TRUE, count;
  885.     int numalltypes = 0, occvolume = 0;
  886.     int numeachtype[MAXUTYPES], sharedeachtype[MAXUTYPES];
  887.     Unit *occ;
  888.  
  889.     for_all_unit_types(u) numeachtype[u] = sharedeachtype[u] = 0;
  890.     /* Eject occupants overflowing counts in shared space. */
  891.     for_all_occupants(unit, occ) ++numeachtype[occ->type];
  892.     for_all_unit_types(u) {
  893.         if (numeachtype[u] > uu_capacity_x(u2, u)) {
  894.         sharedeachtype[u] = numeachtype[u] - uu_capacity_x(u2, u);
  895.         if (uu_occ_max(u2, u) >= 0
  896.             && sharedeachtype[u] > uu_occ_max(u2, u)) {
  897.                 count = sharedeachtype[u] - uu_occ_max(u2, u);
  898.                 while (count > 0) {
  899.                     for_all_occupants(unit, occ) {
  900.                         if (occ->type == u) {
  901.                             eject_occupant(unit, occ);
  902.                             --count;
  903.                             break;
  904.                         }
  905.                     }
  906.                 }
  907.         }
  908.     }
  909.     }
  910.     /* Eject occupants over the total max count allowed. */
  911.     for_all_occupants(unit, occ) ++numalltypes;
  912.     if (u_occ_total_max(u2) >= 0 && numalltypes > u_occ_total_max(u2)) {
  913.         count = numalltypes - u_occ_total_max(u2);
  914.         while (unit->occupant != NULL) {
  915.         eject_occupant(unit, unit->occupant);
  916.         if (--count <= 0) break;
  917.         }
  918.     }
  919.     /* Eject occupants overflowing volume of shared space. */
  920.     while (overfull) {
  921.     for_all_unit_types(u) numeachtype[u] = 0;
  922.     occvolume = 0;
  923.     for_all_occupants(unit, occ) ++numeachtype[occ->type];
  924.     for_all_unit_types(u) {
  925.         occvolume +=
  926.              max(0, numeachtype[u] - uu_capacity_x(u2, u)) * uu_size(u, u2);
  927.     }
  928.     if (occvolume > u_capacity(u2)) {
  929.         overfull = TRUE;
  930.         eject_occupant(unit, unit->occupant);
  931.     } else {
  932.         overfull = FALSE;
  933.     }
  934.     }
  935. }
  936.  
  937. /* Given that an occupant must leave its transport, decide what happens; either
  938.    move out into the open, into another unit, or vanish. */
  939.  
  940. /* (should be generic test) */
  941. #define ut_dies_on(u, t) (ut_vanishes_on(u,t) || ut_wrecks_on(u, t))
  942.  
  943. void
  944. eject_occupant(unit, occ)
  945. Unit *unit, *occ;
  946. {
  947.     if (!in_play(unit) || !in_play(occ)) return;
  948.     /* If the occupant is mobile and the current cell has room, let it escape
  949.        but be stacked in the transport's cell. */
  950.     if (mobile(occ->type)
  951.         && !ut_dies_on(occ->type, terrain_at(unit->x, unit->y))
  952.         && can_occupy_cell(occ, unit->x, unit->y)) {
  953.         leave_cell(occ);
  954.         enter_cell(occ, unit->x, unit->y);
  955.         return;
  956.     }
  957.     /* (should let occupants escape into other units in cell) */
  958.     /* (should let occupants with acp escape into adj cells) */
  959.     /* Evaporating the occupant is our last option. */
  960.     kill_unit(occ, H_UNIT_KILLED);
  961. }
  962.  
  963. /* Handle the general situation of a unit changing allegiance from one side
  964.    to another.  This is a common internal routine, so no messages here. */
  965.  
  966. void
  967. unit_changes_side(unit, newside, reason1, reason2)
  968. Unit *unit;
  969. Side *newside;
  970. int reason1, reason2;
  971. {
  972.     int ux = unit->x, uy = unit->y;
  973.     Side *oldside = unit->side;
  974.     Unit *occ;
  975.  
  976.     if (oldside == newside)
  977.       return;
  978.     if (!unit_allowed_on_side(unit, newside)) {
  979.     if (reason1 == H_UNIT_CAPTURED)
  980.       kill_unit(unit, H_UNIT_KILLED);
  981.     return;
  982.     }
  983.     /* Give captured units some additional moves maybe. */
  984. #if 0
  985.     if (reason1 == CAPTURE)
  986.       unit->movesleft = (period_capturemoves() ? compute_move(unit) : 0);
  987. #endif
  988.     /* Remove unit from former side's inventory and counts. */
  989.     if (oldside != NULL) {
  990. /*    oldside->units[unit->type]--;  */
  991. /*    if (reason2 >= 0) side_balance(oldside, unit->type, reason2)++; */
  992.     update_unit_display(oldside, unit, TRUE);
  993.     /* for machine players */
  994. /*    if (reason2 == PRISONER) register_loss_to_area(oldside, unit, 2);  */
  995.     }
  996.     /* Add unit to new side's inventory and counts. */
  997.     if (newside != NULL) {
  998. /*    newside->units[unit->type]++;  */
  999. /*        if (reason1 >= 0) side_balance(newside, unit->type, reason1)++; */
  1000.     }
  1001.     /* (Should this be switchable maybe?) */
  1002.     for_all_occupants(unit, occ) {
  1003.     unit_changes_side(occ, newside, reason1, reason2);
  1004.     }
  1005.     /* Adjust view coverage.  The sequencing here is to make sure that no
  1006.        viewing coverage gets left on or off inadvertantly. */
  1007.     if (alive(unit) && inside_area(ux, uy)) {
  1008.     /* Uncover the current viewed area. */
  1009.     cover_area(unit->side, unit, ux, uy, -1);
  1010.     /* Actually set the side slot of the unit here. */
  1011.     set_unit_side(unit, newside);
  1012.     /* Cover it for the new side now. */
  1013.     cover_area(unit->side, unit, ux, uy, 1);
  1014.     /* A freebie for the unit's previous side. */
  1015.     see_exact(oldside, ux, uy);
  1016.     }
  1017.     /* Reflect the changeover in any appropriate displays. */
  1018.     if (oldside != NULL && oldside != indepside) {
  1019.     update_unit_display(oldside, unit, TRUE); /* a second update? */
  1020.     }
  1021.     if (newside != NULL && newside != indepside) {
  1022.     update_unit_display(newside, unit, TRUE);
  1023.     }
  1024. }
  1025.  
  1026. /* This is a general test as to whether the given unit can be
  1027.    on the given side. */
  1028.  
  1029. int
  1030. unit_allowed_on_side(unit, side)
  1031. Unit *unit;
  1032. Side *side;
  1033. {
  1034.     if (unit == NULL) return FALSE;
  1035.     /* (allow for tests on individual units also?) */
  1036.     return type_allowed_on_side(unit->type, side);
  1037. }
  1038.  
  1039. int
  1040. test_class_membership(leaf)
  1041. Obj *leaf;
  1042. {
  1043.     char *sclass;
  1044.  
  1045.     if (stringp(leaf)) {
  1046.     sclass = c_string(leaf);
  1047.     if (tmpside != NULL) {
  1048.         if (empty_string(tmpside->sideclass)) return FALSE;
  1049.         return (strcmp(sclass, tmpside->sideclass) == 0);
  1050.     } else {
  1051.         return (strcmp(sclass, "independent") == 0);
  1052.     }
  1053.     } else {
  1054.     init_warning("testing side against garbled class expression");
  1055.     /* Be permissive if continued. */
  1056.     return TRUE;
  1057.     }
  1058. }
  1059.  
  1060. int
  1061. type_allowed_on_side(u, side)
  1062. int u;
  1063. Side *side;
  1064. {
  1065.     Obj *sclass = u_possible_sides(u);
  1066.  
  1067.     /* (could optimize by precomputing bit vectors) */
  1068.     tmputype = u;
  1069.     tmpside = side;
  1070.     return eval_boolean_expression(sclass, test_class_membership, TRUE);
  1071. }
  1072.  
  1073. int
  1074. unit_trusts_unit(unit1, unit2)
  1075. Unit *unit1, *unit2;
  1076. {
  1077.     return (unit1->side == unit2->side
  1078.         || trusted_side(unit1->side, unit2->side));
  1079. }
  1080.  
  1081. /* Put the given unit on the given side, without all the fancy effects.
  1082.    Important to handle independents, because this gets called during init.
  1083.    This is the only way that a unit's side may be altered. */
  1084.  
  1085. /* Note that this may be run on dead units, as part of clearing out a
  1086.    side's units, in which case we just want to relink, don't care about
  1087.    testing whether the type is allowed or not. */
  1088.  
  1089. int
  1090. set_unit_side(unit, side)
  1091. Unit *unit;
  1092. Side *side;
  1093. {
  1094.     Side *oldside, *newside;
  1095.  
  1096.     if (unit->side != side) {
  1097.     /* Subtract from the counts for the ex-side. */
  1098.     oldside = (unit->side ? unit->side : indepside);
  1099.     if (oldside->numunits)
  1100.       --(oldside->numunits[unit->type]);
  1101.     if (oldside->numlive && in_play(unit))
  1102.       --(oldside->numlive[unit->type]);
  1103.     /* Set the unit's slot. */
  1104.     /* Note that indep units have a NULL side, even though there
  1105.        is an actual side object for independents. */
  1106.     unit->side = side;
  1107.     /* Make sure this unit is off anybody else's list. */
  1108.     delete_unit(unit);
  1109.     newside = (side ? side : indepside);
  1110.     insert_unit(newside->unithead, unit);
  1111.     /* Add to counts for the side. */
  1112.     if (newside->numunits)
  1113.       ++(newside->numunits[unit->type]);
  1114.     if (newside->numlive && in_play(unit))
  1115.       ++(newside->numlive[unit->type]);
  1116.     }
  1117.     return TRUE;
  1118. }
  1119.  
  1120. void
  1121. set_unit_plan_type(side, unit, type)
  1122. Side *side;
  1123. Unit *unit;
  1124. int type;
  1125. {
  1126.     int oldtype;
  1127.  
  1128.     if (unit->plan) {
  1129.     oldtype = unit->plan->type;
  1130.     if (type != oldtype) {
  1131.         unit->plan->type = type;
  1132.         if (side != NULL)
  1133.           update_unit_display(side, unit, TRUE);
  1134.     }
  1135.     }
  1136. }
  1137.  
  1138. void
  1139. set_unit_asleep(side, unit, flag, recurse)
  1140. Side *side;
  1141. Unit *unit;
  1142. int flag, recurse;
  1143. {
  1144.     int oldflag;
  1145.     Unit *occ;
  1146.  
  1147.     if (unit->plan) {
  1148.     oldflag = unit->plan->asleep;
  1149.     if (flag != oldflag) {
  1150.         unit->plan->asleep = flag;
  1151.         if (side != NULL)
  1152.           update_unit_display(side, unit, TRUE);
  1153.     }
  1154.     }
  1155.     if (recurse) {
  1156.         for_all_occupants(unit, occ) {
  1157.         set_unit_asleep(side, occ, flag, recurse);
  1158.         }
  1159.     }
  1160. }
  1161.  
  1162. void
  1163. set_unit_reserve(side, unit, flag, recurse)
  1164. Side *side;
  1165. Unit *unit;
  1166. int flag, recurse;
  1167. {
  1168.     int oldflag;
  1169.     Unit *occ;
  1170.  
  1171.     if (unit->plan) {
  1172.     oldflag = unit->plan->reserve;
  1173.     if (flag != oldflag) {
  1174.         unit->plan->reserve = flag;
  1175.         if (side != NULL)
  1176.           update_unit_display(side, unit, TRUE);
  1177.     }
  1178.     }
  1179.     if (recurse) {
  1180.         for_all_occupants(unit, occ) {
  1181.         set_unit_reserve(side, occ, flag, recurse);
  1182.         }
  1183.     }
  1184. }
  1185.  
  1186. void
  1187. set_unit_ai_control(side, unit, flag, recurse)
  1188. Side *side;
  1189. Unit *unit;
  1190. int flag, recurse;
  1191. {
  1192.     int oldflag;
  1193.     Unit *occ;
  1194.  
  1195.     if (unit->plan) {
  1196.     oldflag = unit->plan->aicontrol;
  1197.     if (flag != oldflag) {
  1198.         unit->plan->aicontrol = flag;
  1199.         if (side != NULL)
  1200.           update_unit_display(side, unit, TRUE);
  1201.     }
  1202.     }
  1203.     if (recurse) {
  1204.         for_all_occupants(unit, occ) {
  1205.         set_unit_ai_control(side, occ, flag, recurse);
  1206.         }
  1207.     }
  1208. }
  1209.  
  1210. void
  1211. set_unit_name(side, unit, newname)
  1212. Side *side;
  1213. Unit *unit;
  1214. char *newname;
  1215. {
  1216.     /* Always turn 0-length names into NULL. */
  1217.     if (newname != NULL && strlen(newname) == 0)
  1218.       newname = NULL;
  1219.     /* Don't do anything if the name didn't actually change. */
  1220.     if ((unit->name == NULL && newname == NULL)
  1221.         || (unit->name != NULL && newname != NULL && strcmp(unit->name, newname) == 0))
  1222.       return;
  1223.     /* Record this in the history. */
  1224.     record_unit_name_change(unit, newname);
  1225.     unit->name = newname;
  1226.     update_unit_display(side, unit, TRUE);
  1227.     update_unit_display(unit->side, unit, TRUE);
  1228.     /* (should also send to any other side directly viewing this unit!) */
  1229. }
  1230.  
  1231. /* Remove a unit from play.  This is different from making it available for
  1232.    reallocation - only the unit flusher can do that.  We remove all the
  1233.    passengers too, recursively.  Sometimes units are "killed twice", so
  1234.    be sure not to run all this twice.  Also count up occupant deaths, being
  1235.    sure not to count the unit itself as an occupant. */
  1236.  
  1237. void
  1238. kill_unit(unit, reason)
  1239. Unit *unit;
  1240. int reason;
  1241. {
  1242.     int u = unit->type, u2, selfdied = FALSE;
  1243.     int ux = unit->x, uy = unit->y;
  1244.  
  1245.     if (alive(unit)) {
  1246.     if (unit->side && unit->side->selfunit == unit)
  1247.       selfdied = TRUE;
  1248.     if (occdeath == NULL)
  1249.       occdeath = (int *) xmalloc(numutypes * sizeof(int));
  1250.     /* Always clear this array. */
  1251.     for_all_unit_types(u2)
  1252.       occdeath[u2] = 0;
  1253.     /* The recursive routine will count this unit's death, so start it
  1254.        out down by one. */
  1255.     occdeath[u] = -1;
  1256.     leave_cell(unit);
  1257.     /* A freebie for the unit's side. */
  1258.     see_exact(unit->side, ux, uy);
  1259.     kill_unit_aux(unit, reason);
  1260.     if (selfdied) {
  1261.         if (u_self_resurrects(u)) {
  1262.         /* should find and designate a new self unit */
  1263.         return;
  1264.         } else {
  1265.         /* Make sure this doesn't have serious consequences? */
  1266.         if (unit->side->ingame)
  1267.           side_loses(unit->side, NULL, -2);
  1268.         /* (can't do all consequences just yet?) */
  1269.         }
  1270.     }
  1271.     recent_dead_flushed = FALSE;
  1272.     }
  1273. }
  1274.  
  1275. /* Trash it now - occupant doesn't need to leave_cell.  Also record the
  1276.    event, and update the apropriate display.  The unit here should
  1277.    be known to be alive. */
  1278.  
  1279. void
  1280. kill_unit_aux(unit, reason)
  1281. Unit *unit;
  1282. int reason;
  1283. {
  1284.     int u = unit->type;
  1285.     Unit *occ;
  1286.     Side *side = unit->side;
  1287.     
  1288.     unit->hp = 0;
  1289.     ++(occdeath[u]);
  1290.     /* Get rid of the unit's plan/tasks.  This should be safe, because
  1291.        unit death should only happen during action execution and in
  1292.        between turns, and plans/tasks should not be in use at those times. */
  1293.     dispose_of_plan(unit);
  1294.     /* Maybe enter the loss into the historical record. */
  1295.     if (reason >= 0)
  1296.       record_unit_loss(unit, reason);
  1297.     if (side != NULL) {
  1298.         react_to_unit_loss(side, unit, reason);
  1299.     update_unit_display(side, unit, TRUE);
  1300.     }
  1301.     /* Kill all the occupants in turn. */
  1302.     for_all_occupants(unit, occ) {
  1303.     if (alive(occ))
  1304.       kill_unit_aux(occ, reason);
  1305.     }
  1306. }
  1307.  
  1308. /* Give strategists a chance to react. */
  1309.  
  1310. void
  1311. react_to_unit_loss(side, unit, reason)
  1312. Side *side;
  1313. Unit *unit;
  1314. int reason;
  1315. {
  1316.     if (side_has_ai(side)) {
  1317.     ai_react_to_unit_loss(side, unit);
  1318.     }
  1319. }
  1320.  
  1321. /* Do something about the plan object, possibly passing to a deputy unit
  1322.    (not implemented yet), or maybe just destroying it entirely. */
  1323.  
  1324. void
  1325. dispose_of_plan(unit)
  1326. Unit *unit;
  1327. {
  1328.     /* Might not be anything to dispose of. */
  1329.     if (unit->plan == NULL)
  1330.       return;
  1331.     free_plan(unit->plan);
  1332.     unit->plan = NULL;
  1333. }
  1334.  
  1335. /* Get rid of all dead units at once.  It's important to get rid of all
  1336.    of the dead units, so they don't come back and haunt us.
  1337.    (This routine is basically a garbage collector, and should not be called
  1338.    during a unit list traversal.) The process starts by finding the first
  1339.    live unit, making it the head, then linking around all in the middle.
  1340.    Dead units stay on the dead unit list for each side until that side has had
  1341.    a chance to move.  Then they are finally flushed in a permanent fashion. */ 
  1342.  
  1343. void
  1344. flush_dead_units()
  1345. {
  1346. #if 0 /* def REUSE_DEAD */
  1347.     Unit *unit, *prevunit;
  1348.     Side *side;
  1349.  
  1350.     /* This never ends up flushing independent units, no big loss. */
  1351.     if (!recent_dead_flushed) {
  1352.     recent_dead_flushed = TRUE;
  1353.     for_all_units(unit) {
  1354.         if (!alive(unit)) {
  1355.         prevunit = unit->prev;
  1356.         delete_unit(unit);
  1357.         put_unit_on_dead_list(unit);
  1358.         unit = prevunit;
  1359.         }
  1360.     }
  1361.     }
  1362. #endif
  1363. }
  1364.  
  1365. /* Put dead units on sides dead unit lists. */
  1366.  
  1367. void
  1368. put_unit_on_dead_list(unit)
  1369. Unit *unit;
  1370. {
  1371. #ifdef REUSE_DEAD
  1372.     if (unit->side == NULL) {
  1373.     flush_one_unit(unit);
  1374.     } else {
  1375.     unit->next = unit->side->deadunits;
  1376.     unit->side->deadunits = unit;
  1377.     }
  1378.     --numunits;
  1379. #endif
  1380. }
  1381.  
  1382. /* Clean up dead units and put them back on free list. */
  1383.  
  1384. void
  1385. flush_side_dead(side)
  1386. Side *side;
  1387. {
  1388. #ifdef REUSE_DEAD
  1389.     Unit *unit, *next;
  1390.  
  1391.     next = side->deadunits;
  1392.     while (next != NULL) {
  1393.     unit = next;
  1394.     next = unit->next;
  1395.     flush_one_unit(unit);
  1396.     }
  1397.     side->deadunits = NULL;
  1398. #endif
  1399. }
  1400.  
  1401. /* Keep it clean - hit all links to other places.  Some might not be
  1402.    strictly necessary, but this is not an area to take chances with. */
  1403.  
  1404. void
  1405. flush_one_unit(unit)
  1406. Unit *unit;
  1407. {
  1408.     unit->id = -1;
  1409.     unit->occupant = NULL;
  1410.     unit->transport = NULL;
  1411.     unit->nexthere = NULL;
  1412.     /* Add it on the list of available units. */
  1413.     unit->next = freeunits;
  1414.     freeunits = unit;
  1415. }
  1416.  
  1417. /* Do multiple passes of bubble sort.
  1418.    Data is generally coherent, so bubble sort not too bad if we allow
  1419.    early termination when everything is already in order.  */
  1420.  
  1421. /* If slowness objectionable, replace with something clever, but be
  1422.    sure that average performance in real games is what's being improved. */
  1423.  
  1424. void
  1425. sort_units()
  1426. {
  1427.     int flips;
  1428.     int passes = 0;
  1429.     register Unit *unit, *nextunit;
  1430.     Side *side;
  1431.  
  1432.     for_all_sides_plus_indep(side) {
  1433.     passes = 0;
  1434.     flips = TRUE;
  1435.     while (flips) {
  1436.         flips = FALSE;
  1437.         for_all_side_units(side, unit) {
  1438.         if (unit->next != side->unithead
  1439.             && compare_units(unit, unit->next) > 0) {
  1440.             flips = TRUE;
  1441.             /* Reorder the units by fiddling with their links. */
  1442.             nextunit = unit->next;
  1443.             unit->prev->next = nextunit;
  1444.             nextunit->next->prev = unit;
  1445.             nextunit->prev = unit->prev;
  1446.             unit->next = nextunit->next;
  1447.             nextunit->next = unit;
  1448.             unit->prev = nextunit;
  1449.         }
  1450.         ++passes;
  1451.         }
  1452.     }
  1453.     }
  1454.     Dprintf("Sorting passes = %d\n", passes);
  1455. }
  1456.  
  1457. static int
  1458. compare_units(unit1, unit2)
  1459. Unit *unit1, *unit2;
  1460. {
  1461.     if (unit1->type != unit2->type)
  1462.       return (unit1->type - unit2->type);
  1463.     if (unit1->name && unit2->name == NULL)
  1464.       return -1;
  1465.     if (unit1->name == NULL && unit2->name)
  1466.       return 1;
  1467.     if (unit1->name && unit2->name)
  1468.       return strcmp(unit1->name, unit2->name);
  1469.     if (unit1->number != unit2->number)
  1470.       return (unit1->number - unit2->number);
  1471.     /* Ids impose a total ordering. */
  1472.     return (unit1->id - unit2->id);
  1473. }
  1474.  
  1475. /* Useful for the machine player to know how long it can move this
  1476.    piece before it should go home.  Assumes can't replenish from
  1477.    terrain.  Result may be negative, in which case it's time to go! */
  1478.  
  1479. int
  1480. moves_till_low_supplies(unit)
  1481. Unit *unit;
  1482. {
  1483.     int u = unit->type, r, moves = 1234567, tmp;
  1484.  
  1485.     for_all_material_types(r) {
  1486.     if ((um_consumption_per_move(u, r) > 0)) {
  1487.         tmp = (unit->supply[r] - um_storage_x(u, r) / 2) / um_consumption_per_move(u, r);
  1488.         moves = min(moves, tmp);
  1489.     }
  1490.     }
  1491.     return moves;
  1492. }
  1493.  
  1494. /* Short, unreadable, but greppable listing of unit.  Primarily useful
  1495.    for debugging and warnings.  We use several buffers and rotate between
  1496.    them so we can call this more than once in a single printf. */
  1497.  
  1498. char *
  1499. unit_desig(unit)
  1500. Unit *unit;
  1501. {
  1502.     char *shortbuf;
  1503.  
  1504.     if (unit == NULL)
  1505.       return "no unit";
  1506.     /* Allocate if not yet done so. */
  1507.     if (shortbufs[curshortbuf] == NULL)
  1508.       shortbufs[curshortbuf] = xmalloc(BUFSIZE);
  1509.     shortbuf = shortbufs[curshortbuf];
  1510.     curshortbuf = (curshortbuf + 1) % NUMSHORTBUFS;
  1511.     if (unit->id == -1) {
  1512.     sprintf(shortbuf, "s%d head", side_number(unit->side));
  1513.     return shortbuf;
  1514.     } else if (is_unit_type(unit->type)) {
  1515.     sprintf(shortbuf, "s%d %-3.3s %d (%d,%d",
  1516.         side_number(unit->side), shortest_unique_name(unit->type),
  1517.         unit->id, unit->x, unit->y);
  1518.     if (unit->z != 0)
  1519.       tprintf(shortbuf, ",%d", unit->z);
  1520.     /* This has the potential to generate some very misleading
  1521.        results, if this routine is called on a unit before its
  1522.        transport field is patched from a Lisp object into a real
  1523.        unit reference. */
  1524.     if (unit->transport)
  1525.       tprintf(shortbuf, ",in%d", unit->transport->id);
  1526.     strcat(shortbuf, ")");  /* close out the unit location */
  1527.     return shortbuf;
  1528.     } else {
  1529.     return "!garbage unit!";
  1530.     }
  1531. }
  1532.  
  1533. /* Short, unreadable, but greppable listing of unit that omits anything
  1534.    that changes from turn to turn. */
  1535.  
  1536. char *
  1537. unit_desig_no_loc(unit)
  1538. Unit *unit;
  1539. {
  1540.     char *shortbuf;
  1541.  
  1542.     if (unit == NULL)
  1543.       return "no unit";
  1544.     /* Allocate if not yet done so. */
  1545.     if (shortbufs[curshortbuf] == NULL)
  1546.       shortbufs[curshortbuf] = xmalloc(BUFSIZE);
  1547.     shortbuf = shortbufs[curshortbuf];
  1548.     curshortbuf = (curshortbuf + 1) % NUMSHORTBUFS;
  1549.     if (unit->id == -1) {
  1550.     sprintf(shortbuf, "s%d head", side_number(unit->side));
  1551.     return shortbuf;
  1552.     } else if (is_unit_type(unit->type)) {
  1553.     sprintf(shortbuf, "s%d %-3.3s %d",
  1554.         side_number(unit->side), shortest_unique_name(unit->type),
  1555.         unit->id);
  1556.     return shortbuf;
  1557.     } else {
  1558.     return "!garbage unit!";
  1559.     }
  1560. }
  1561.  
  1562. /* Come up with a unit type name that fits in the given space. */
  1563.  
  1564. char *
  1565. utype_name_n(u, n)
  1566. int u, n;
  1567. {
  1568.     char *utypename, *shortname, *rawname;
  1569.  
  1570.     utypename = u_type_name(u);
  1571.     if (n <= 0 || strlen(utypename) <= n) {
  1572.     return utypename;
  1573.     } else if (n == 1 && !empty_string(u_uchar(u))) {
  1574.     /* Use the unit char if possible. */
  1575.     return u_uchar(u);
  1576.     } else if (!empty_string(u_short_name(u))) {
  1577.         shortname = u_short_name(u);
  1578.     if (strlen(shortname) <= n) {
  1579.         return shortname;
  1580.     } else {
  1581.         rawname = shortname;
  1582.     }
  1583.     } else {
  1584.         rawname = utypename;
  1585.     }
  1586.     /* Copy what will fit. */
  1587.     strncpy(utypenamen, rawname, n);
  1588.     utypenamen[n] = '\0';
  1589.     return utypenamen;
  1590. }
  1591.  
  1592. char **shortestnames = NULL;
  1593.  
  1594. char *
  1595. shortest_unique_name(u)
  1596. int u;
  1597. {
  1598.     char namebuf[BUFSIZE], *name1;
  1599.     int u1, u2, i, allhavechars, firstuniq[MAXUTYPES], firstuniq1;
  1600.  
  1601.     if (shortestnames == NULL) {
  1602.     shortestnames = (char **) xmalloc(numutypes * sizeof(char *));
  1603.     allhavechars = TRUE;
  1604.     for_all_unit_types(u1) {
  1605.         if (!empty_string(u_uchar(u1))) {
  1606.         namebuf[0] = (u_uchar(u1))[0];
  1607.         namebuf[1] = '\0';
  1608.         shortestnames[u1] = copy_string(namebuf);
  1609.         } else {
  1610.         allhavechars = FALSE;
  1611.         }
  1612.     }
  1613.     if (!allhavechars) {
  1614.         for_all_unit_types(u1) {
  1615.         shortestnames[u1] = copy_string(u_type_name(u1));
  1616.         firstuniq[u1] = 0;
  1617.         }
  1618.         for_all_unit_types(u1) {
  1619.         name1 = shortestnames[u1];
  1620.         firstuniq1 = firstuniq[u1];
  1621.         for_all_unit_types(u2) {
  1622.             if (u1 != u2) {
  1623.             for (i = 0; i < firstuniq1; ++i ) {
  1624.                 if (name1[i] != (shortestnames[u2])[i]) {
  1625.                 break;
  1626.                 }
  1627.             }
  1628.             if (i == firstuniq1) {
  1629.                 while (name1[firstuniq1] == (shortestnames[u2])[firstuniq1]) {
  1630.                 ++firstuniq1;
  1631.                 }
  1632.             }
  1633.             }
  1634.         }
  1635.         firstuniq[u1] = firstuniq1;
  1636.         }
  1637.         for_all_unit_types(u1) {
  1638.         if (firstuniq[u1] + 1 < strlen(shortestnames[u1])) {
  1639.             (shortestnames[u1])[firstuniq[u1] + 1] = '\0';
  1640.         }
  1641.         }
  1642.     }
  1643.     }
  1644.     return shortestnames[u];
  1645. }
  1646.  
  1647. /* This formats an actorstate readably. */
  1648.  
  1649. char *
  1650. actorstate_desig(as)
  1651. ActorState *as;
  1652. {
  1653.     if (actorstatebuf == NULL) actorstatebuf = xmalloc(BUFSIZE);
  1654.     if (as != NULL) {
  1655.     sprintf(actorstatebuf, "acp %d/%d %s",
  1656.         as->acp, as->initacp, action_desig(&(as->nextaction)));
  1657.     return actorstatebuf;
  1658.     } else {
  1659.     return "no act";
  1660.     }
  1661. }
  1662.  
  1663. /* Search for a unit with the given id number. */
  1664.  
  1665. /* This is used a lot, it should be sped up. */
  1666.  
  1667. Unit *
  1668. find_unit(n)
  1669. int n;
  1670. {
  1671.     Unit *unit;
  1672.  
  1673.     for_all_units(unit) {
  1674.     if (alive(unit) && unit->id == n)
  1675.       return unit;
  1676.     }
  1677.     return NULL;
  1678. }
  1679.  
  1680. /* Find a unit with the given name, either alive or dead. */
  1681.  
  1682. Unit *
  1683. find_unit_by_name(nm)
  1684. char *nm;
  1685. {
  1686.     Unit *unit;
  1687.  
  1688.     if (nm == NULL) return NULL;
  1689.     for_all_units(unit) {
  1690.     if (unit->name != NULL && strcmp(unit->name, nm) == 0)
  1691.       return unit;
  1692.     }
  1693.     return NULL;
  1694. }
  1695.  
  1696. /* Find a unit with the given number, either alive or dead. */
  1697.  
  1698. Unit *
  1699. find_unit_by_number(nb)
  1700. int nb;
  1701. {
  1702.     Unit *unit;
  1703.  
  1704.     for_all_units(unit) {
  1705.     if (unit->number == nb)
  1706.       return unit;
  1707.     }
  1708.     return NULL;
  1709. }
  1710.  
  1711. Unit *
  1712. find_unit_dead_or_alive(n)
  1713. int n;
  1714. {
  1715.     Unit *unit;
  1716.  
  1717.     for_all_units(unit) {
  1718.     if (unit->id == n)
  1719.       return unit;
  1720.     }
  1721.     return NULL;
  1722. }
  1723.  
  1724. /* Given a name, find the type. */
  1725.  
  1726. int
  1727. find_unit_name(str)
  1728. char *str;
  1729. {
  1730.     int u;
  1731.  
  1732.     for_all_unit_types(u)
  1733.       if (strcmp(str, u_short_name(u)) == 0
  1734.       || strcmp(str, u_type_name(u)) == 0) 
  1735.     return u;
  1736.     return NONUTYPE;
  1737. }
  1738.  
  1739. /* Insert the given unit after the other given unit. */
  1740.  
  1741. void
  1742. insert_unit(unithead, unit)
  1743. Unit *unithead, *unit;
  1744. {
  1745.     unit->next = unithead->next;
  1746.     unit->prev = unithead;
  1747.     unithead->next->prev = unit;
  1748.     unithead->next = unit;
  1749. }
  1750.  
  1751. /* Delete the unit from its list. */
  1752.  
  1753. void
  1754. delete_unit(unit)
  1755. Unit *unit;
  1756. {
  1757.     unit->next->prev = unit->prev;
  1758.     unit->prev->next = unit->next;
  1759. }
  1760.  
  1761. int
  1762. num_occupants(unit)
  1763. Unit *unit;
  1764. {
  1765.     int num = 0;
  1766.     Unit *occ;
  1767.  
  1768.     for_all_occupants(unit, occ) {
  1769.     num += 1;
  1770.     }
  1771.     return num;
  1772. }
  1773.  
  1774. int
  1775. num_units_at(x, y)
  1776. int x, y;
  1777. {
  1778.     int num = 0;
  1779.     Unit *unit;
  1780.  
  1781.     x = wrapx(x);
  1782.     if (!in_area(x, y)) {
  1783.     run_warning("num_units_at %d,%d??", x, y);
  1784.     return 0;
  1785.     }
  1786.     for_all_stack(x, y, unit) {
  1787.     num += 1;
  1788.     }
  1789.     return num;
  1790. }
  1791.  
  1792. /* Call this to doublecheck invariants on units. */
  1793.  
  1794. void
  1795. check_all_units()
  1796. {
  1797.     Unit *unit;
  1798.  
  1799.     for_all_units(unit) {
  1800.     check_unit(unit);
  1801.     }
  1802. }
  1803.  
  1804. void
  1805. check_unit(unit)
  1806. Unit *unit;
  1807. {
  1808.     if (alive(unit) && unit->transport && !alive(unit->transport)) {
  1809.         run_warning("%s is inside a dead transport", unit_desig(unit));
  1810.     }
  1811.     /* etc */
  1812. }
  1813.  
  1814. #ifdef DESIGNERS
  1815.  
  1816. /* Move a unit to a given location instantly, with all sides observing.
  1817.    This is for use by designers only! */
  1818.  
  1819. void
  1820. designer_teleport(unit, x, y)
  1821. Unit *unit;
  1822. int x, y;
  1823. {
  1824.     leave_cell(unit);
  1825.     enter_cell(unit, x, y);
  1826.     all_see_cell(x, y);
  1827. }
  1828.  
  1829. #endif /* DESIGNERS */
  1830.  
  1831. UnitVector *
  1832. make_unit_vector(initsize)
  1833. int initsize;
  1834. {
  1835.     UnitVector *vec;
  1836.     
  1837.     vec = (UnitVector *)
  1838.       xmalloc(sizeof(UnitVector) + initsize * sizeof(UnitVectorEntry));
  1839.     vec->size = initsize;
  1840.     vec->numunits = 0;
  1841.     return vec;
  1842. }
  1843.  
  1844. void
  1845. clear_unit_vector(vec)
  1846. UnitVector *vec;
  1847. {
  1848.     vec->numunits = 0;
  1849. }
  1850.  
  1851. UnitVector *
  1852. add_unit_to_vector(vec, unit, flag)
  1853. UnitVector *vec;
  1854. Unit *unit;
  1855. int flag;
  1856. {
  1857.     int i;
  1858.     UnitVector *newvec;
  1859.  
  1860.     /* (should search to see if already present) */
  1861.     if (vec->numunits >= vec->size) {
  1862.     newvec = make_unit_vector((3 * vec->size) / 2);
  1863.     newvec->numunits = vec->numunits;
  1864.     for (i = 0; i < vec->numunits; ++i) {
  1865.         newvec->units[i] = vec->units[i];
  1866.     }
  1867.     vec = newvec;
  1868.     }
  1869.     ((vec->units)[vec->numunits]).unit = unit;
  1870.     ((vec->units)[vec->numunits]).flag = flag;
  1871.     ++(vec->numunits);
  1872.     return vec;
  1873. }
  1874.  
  1875. void
  1876. remove_unit_from_vector(vec, unit, pos)
  1877. UnitVector *vec;
  1878. Unit *unit;
  1879. int pos;
  1880. {
  1881.     int j;
  1882.  
  1883.     if (pos < 0) {
  1884.     /* should search for unit in vector */
  1885.     }
  1886.     if (unit != vec->units[pos].unit)
  1887.       run_error("unit mismatch in remove_unit_from_vector, %s not at %d",
  1888.         unit_desig(unit), pos);    
  1889.     for (j = pos + 1; j < vec->numunits; ++j)
  1890.       vec->units[j-1] = vec->units[j];
  1891.     --(vec->numunits);
  1892. }
  1893.  
  1894. enum sortkeys tmpsortkeys[MAXSORTKEYS];
  1895.  
  1896. static int
  1897. compare_units_by_keys(e1, e2)
  1898. CONST void *e1, *e2;
  1899. {
  1900.     int i;
  1901.     Unit *unit1 = ((UnitVectorEntry *) e1)->unit, *unit2 = ((UnitVectorEntry *) e2)->unit;
  1902.     
  1903.     if (unit1 == unit2) return 0;
  1904.     if (unit1 == NULL) return 1;
  1905.     if (unit2 == NULL) return -1;
  1906.     for (i = 0; i < MAXSORTKEYS; ++i) {
  1907.     switch (tmpsortkeys[i]) {
  1908.       case byside:
  1909.         if (unit1->side != unit2->side) {
  1910.         int s1 = side_number(unit1->side);
  1911.         int s2 = side_number(unit2->side);
  1912.         
  1913.         /* Put independents at the end of any list. */
  1914.         if (s1 == 0) s1 = numsides + 1;
  1915.         if (s2 == 0) s2 = numsides + 1;
  1916.         return (s1 - s2);
  1917.         }
  1918.         break;
  1919.       case bytype:
  1920.         if (unit1->type != unit2->type) {
  1921.         return (unit1->type - unit2->type);
  1922.         }
  1923.         break;
  1924.       case byname:
  1925.         if (unit1->name) {
  1926.         if (unit2->name) {
  1927.             return strcmp(unit1->name, unit2->name);
  1928.         } else {
  1929.             return -1;
  1930.         }
  1931.         } else if (unit1->number > 0) {
  1932.         if (unit2->name) {
  1933.             return 1;
  1934.         } else if (unit2->number > 0) {
  1935.             return (unit1->number - unit2->number);
  1936.         } else {
  1937.             return -1;
  1938.         }
  1939.         } else if (unit2->name) {
  1940.         return 1;
  1941.         } else if (unit2->number > 0) {
  1942.         return 1;
  1943.         }
  1944.         break;
  1945.       case byactorder:
  1946.         /* (should sort by action priority?) */
  1947.         break;
  1948.       case bylocation:
  1949.         if (unit1->y != unit2->y) {
  1950.         return (unit2->y - unit1->y);
  1951.         } else if (unit1->x != unit2->x) {
  1952.         return (unit1->x - unit2->x);
  1953.         } else {
  1954.         /* Both units are at the same location. Sort by transport. */
  1955.         if (unit1->transport) {
  1956.             if (unit2->transport) {
  1957.             } else {
  1958.             return 1;
  1959.             }
  1960.         } else {
  1961.             if (unit2->transport) {
  1962.             return -1;
  1963.             } else {
  1964.             }
  1965.         }
  1966.         }
  1967.         break;
  1968.       case bynothing:
  1969.         return (unit1->id - unit2->id);
  1970.       default:
  1971.         break;
  1972.     }
  1973.     }
  1974.     /* Unit ids are all unique, so this is a reliable default sort key. */
  1975.     return (unit1->id - unit2->id);
  1976. }
  1977.  
  1978. void
  1979. sort_unit_vector(vec)
  1980. UnitVector *vec;
  1981. {
  1982.     qsort(vec->units, vec->numunits, sizeof(UnitVectorEntry),
  1983.       compare_units_by_keys);
  1984. }
  1985.  
  1986. Obj *
  1987. get_x_property(unit, subkey)
  1988. Unit *unit;
  1989. int subkey;
  1990. {
  1991.     Obj *lis, *bdg;
  1992.  
  1993.     for (lis = unit->hook; lis != lispnil; lis = cdr(lis)) {
  1994.     bdg = car(lis);
  1995.     if (symbolp(car(bdg)) && keyword_code(c_string(car(bdg))) == subkey)
  1996.       return cdr(bdg);
  1997.     }
  1998.     return lispnil;
  1999. }
  2000.  
  2001. Obj *
  2002. get_x_property_by_name(unit, str)
  2003. Unit *unit;
  2004. char *str;
  2005. {
  2006.     Obj *lis, *bdg;
  2007.  
  2008.     for (lis = unit->hook; lis != lispnil; lis = cdr(lis)) {
  2009.     bdg = car(lis);
  2010.     if (symbolp(car(bdg)) && strcmp(c_string(car(bdg)), str) == 0) {
  2011.         return cdr(bdg);
  2012.     }
  2013.     }
  2014.     return lispnil;
  2015. }
  2016.  
  2017.